package pegpeg.client;

import java.util.ArrayList;

import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.canvas.dom.client.CssColor;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Pegpeg implements EntryPoint {
	static final String holderId = "canvasholder";
	static final int tril = 500;
	static final String upgradeMessage = "Your browser does not support the HTML5 Canvas. Please upgrade your browser to view this demo.";

	private Button undoButton = new Button("Undo");
	private Button redoButton = new Button("Redo");
	private Button restartButton = new Button("Restart");
	private VerticalPanel mainPanel = new VerticalPanel();
	private HorizontalPanel controlPanel = new HorizontalPanel();
	
	ArrayList<PegGroup> peglist;

	Canvas canvas;
	PegGroup currentPeg;
	int currentStep;

	// canvas size, in px
	static final int height = 600;
	static final int width = 600;
	static final String boardcolor = "#AFEEEE";

	final CssColor redrawColor = CssColor.make("rgba(255,255,255,0.6)");
	Context2d context;

	public void onModuleLoad() {
		canvas = Canvas.createIfSupported();
		if (canvas == null) {
			RootPanel.get(holderId).add(new Label(upgradeMessage));
			return;
		}

		// init the canvases
		canvas.setWidth(width + "px");
		canvas.setHeight(height + "px");
		canvas.setCoordinateSpaceWidth(width);
		canvas.setCoordinateSpaceHeight(height);

		//Assemble control panel
		controlPanel.add(undoButton);
		controlPanel.add(redoButton);
		controlPanel.add(restartButton);
		
		// Assemble Main panel.
		mainPanel.add(controlPanel);
		mainPanel.add(canvas);

		RootPanel.get(holderId).add(mainPanel);
		context = canvas.getContext2d();

		// init the objects
		restart();	
		
		// init handlers
		initHandlers();
		drawBoard();
	}


	void doUpdate(MouseUpEvent event) {
		int mouseX = event.getRelativeX(canvas.getElement());
		int mouseY = event.getRelativeY(canvas.getElement());
		boolean newMove = currentPeg.update(mouseX, mouseY);
		if(newMove){
			// remove element in peglist between current and tail
			for(int i = currentStep+1; i<peglist.size();)
				peglist.remove(i);
			
			peglist.add(new PegGroup(currentPeg));
			currentStep++;
		}
		drawBoard();
	}

	void drawBoard() {
		context.setFillStyle("#F8F8FF");
		context.setFillStyle(redrawColor);
		context.fillRect(0, 0, width, height);

		context.setFillStyle(boardcolor);
		context.setLineWidth(1);
		context.save();
		context.beginPath();
		context.moveTo(width/2,height/2-Math.sqrt(3)*tril*0.5*0.5);
		context.lineTo(width/2-250,height/2+Math.sqrt(3)*tril*0.5*0.5);
		context.lineTo(width/2+250,height/2+Math.sqrt(3)*tril*0.5*0.5);
		context.setLineJoin ("MITER"); 
		context.closePath();
		context.setShadowColor("#bbbbbb");
		context.setShadowBlur(10);
		context.setShadowOffsetX(15);
		context.setShadowOffsetY (15);
		context.fill();
		context.restore();

		currentPeg.draw(context);
	}

	private void undo() {
		if (currentStep > 0) {
			currentStep--;
			currentPeg = new PegGroup(peglist.get(currentStep));	
		}
	}
	
	private void redo() {
		if (currentStep+1 < peglist.size()) {
			currentStep++;
			currentPeg = new PegGroup(peglist.get(currentStep));
		}
	}
	
	private void restart() {
		currentStep = -1;
		currentPeg = new PegGroup(width, height);
		peglist = new ArrayList<PegGroup>();
		peglist.add(new PegGroup(currentPeg));
		currentStep++;
	}


	void initHandlers() {
		canvas.addMouseUpHandler(new MouseUpHandler() {
			@Override
			public void onMouseUp(MouseUpEvent event) {
				doUpdate(event);
			}	
		});

		// Listen for mouse events on the undo button.
		undoButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				undo();
				drawBoard();
			}
		});

		// Listen for mouse events on the redo button.
		redoButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				redo();
				drawBoard();
			}
		});
		
		// Listen for mouse events on the restart button.
		restartButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				restart();
				drawBoard();
			}
		});
	}
}

